package protocol.pv;
/*
 * Created on 2004-8-12
 *
 * To change the template for this generated file go to
 * Window&gt;Preferences&gt;Java&gt;Code Generation&gt;Code and Comments
 */
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import model.collect.pedEvent;

import org.apache.log4j.Logger;

import protocol.Command;
import protocol.CommandException;

import com.stone.protocol.CommandParserException;

import core.ProcessThread;
import core.upintf.DMClient;
import process.DevStatusProcessor;
import process.gettimeProcessor;




/**
 * 
 * @author pdv
 *
 * Object used to parse a received message.  
 * Message takes the form "commandidTABp1:p1valueTABp2:p2value...".
 * Char to separate tokens in command and param-value pair can be configured and will take default value of '\t', ':'.
 * There can be more or zero token-separator before or after message and one or more token-separator between tokens.
 * Message should at least contains source destination and commandid, or it will be considered invalid.
 */
public class PVCommand extends Command{
	
	private String versionID;
    //separator between subparts of a message, default value is '\t'
	private char commandSeparator;
	//separator between the pair of param and param value, default value is ':'
	private char paramSeparator;
	//message received, buffered to be process.
	private String command;
	private int index;
	private String commandID;
	//the haspmap containing param and param value pairs.
	private HashMap paramValuePairs = new HashMap();
	
	private Object source = null;
	private Object destination = null;
	//do not prevent of out of bound erros.
	private char getChar() {
		char res = command.charAt(index);
		index++;
		return res;
	}
	private boolean isWhite() {
		return (command.charAt(index) == commandSeparator);
	}
	private boolean atEnd() {
		return (index > command.length()-1);
	}
	private void skipWhite() {
		while (!atEnd() && isWhite()) {
				index++;
		}
	}
	private String getNextToken() {
		skipWhite();
		StringBuffer strbuf = new StringBuffer();
		while ((!atEnd()) && (!isWhite())) 			
			strbuf.append(getChar());
		return strbuf.toString();
	}
	
	private void putParamValuePair(String param) 
		throws PVCommandException {
		int sepIndex = param.indexOf(paramSeparator);
		if (sepIndex == -1) 
			throw new PVCommandException("no paramSeparator found");
		String key = param.substring(0, sepIndex);
		String val = "";
		try {
			val = param.substring(sepIndex+1);
		} catch (IndexOutOfBoundsException e) {}
		paramValuePairs.put(key, val);	
	}
	
	
	public PVCommand(String commandID, String versionID, char cmdSep, char paramSep) {
		super();
		if (versionID.equals("") || commandID.equals(""))
			throw new IllegalArgumentException();
		this.commandID = commandID;
		this.versionID = versionID;
		this.commandSeparator = cmdSep;
		this.paramSeparator = paramSep;
		this.setRtCmdPriority();
	}
	
	
	public PVCommand(String commandID) {
		this(commandID, "v1", '\t', ':');
	}
	
	public void setDestination(Object dest) {
		this.destination = dest;
	}
	
	public Object getDestination() {
		return this.destination;
	}
	
	public void setSource(Object source) {
		this.source = source;
	}
	
	public Object getSource() {
		return this.source;
	}
	
	public PVCommand() {
		super();
	}
	
	public void put(String key, String value) {
		this.paramValuePairs.put(key, value);
	}
	
	public void put(String param, int value) {
		put(param, Integer.toString(value));
	
	}
	/**
	 * Constructor
	 * token-separator and param-value separator take default values
	 * @param cmd message to parse
	 * @throws CommandParserException when message received is invalid
	 */
	public static PVCommand genPVCommand(String cmd) 
		throws PVCommandException { 
		return genPVCommand(cmd, '\t', ':');	
	}
	/**
	 * Constructor
	 * @param cmd message to parse
	 * @param cmdSep token-separator
	 * @param paramSep param-value separator
	 * @throws CommandParserException when message received is invalid
	 */
	public static PVCommand genPVCommand(String cmd, char cmdSep, char paramSep) 
		throws PVCommandException {
		PVCommand result = new PVCommand();
		result.command = cmd;
		result.index = 0;
		result.commandSeparator = cmdSep;
		result.paramSeparator = paramSep;
		result.versionID = result.getNextToken();
		result.commandID = result.getNextToken();
		String param = result.getNextToken();
		while (!(param.equals(""))) {
			result.putParamValuePair(param);
			param = result.getNextToken();
		}
		result.setRtCmdPriority();
		return result;
	}
	
	//����
	public static final String SOCKET_BEAT = "ACTIVETEST";
	//stdt
	public static final String DPLD_RTVALIDCUR="DPLD_RTVALIDCUR";
	public static final String DPLD_RTLOADERFACTOR= "DPLD_RTLOADERFACTOR";
	
	public static final String DPLD_RTTOUCHOVERLOAD = "DPLD_RTTOUCHOVERLOAD";
	
	public static final String PMU_RT_S ="pmu_rt_s";
	public static final String IEC104_YC_S= "iec104_yc_s";
	public static final String IEC104_YX_S= "iec104_yx_s";
	
	public static final String PMU_SET_C = "pmu_set";
	public static final String PMU_SET_IP = "pmu_set_ip";
	public static final String PMU_SET_TIMESVR= "pmu_set_timesvr";
	
	//alarm
	public static final String PMU_CUR_AlARM ="pmu_cur_alarm";
	public static final String  LEN_QUEUE="lane_queue";
	public static final String PHASEINFO = "phaseInfo";
	
	private interface PVCommandDecoder {
		public void decode(PVCommand command, ProcessThread thd) throws Exception;
	}
	
	private static Map<String, PVCommandDecoder> decoderMap = new HashMap<String, PVCommandDecoder>();
	
	static {
		
		decoderMap.put("devstatus", new PVCommandDecoder() {
			public void decode(PVCommand command, ProcessThread thd) throws Exception {
				DevStatusProcessor.INSTANCE.processRtData(command, thd);
				
			}
		});
		decoderMap.put("get_time", new PVCommandDecoder() {
			public void decode(PVCommand command, ProcessThread thd) throws Exception {
				gettimeProcessor.INSTANCE.processRtData(command, thd);
				
			}
		});
		decoderMap.put("networkinfo", new PVCommandDecoder() {
			public void decode(PVCommand command, ProcessThread thd) throws Exception {
				logger.info(command.toString());
				
			}
		});
		
	}
	
	/**
	 * 
	 * @return command ID
	 */
	public String getCommandID() {
		return commandID;
	}
	
	public void setCommandID(String cmdID) {
		this.commandID = cmdID;
	}
	/**
	 * @param param parameter Name
	 * @return value of the param, when not exist, return null
	 */
	public String getValue(String param) {
		return (String)(paramValuePairs.get(param));
	}
	
	/**
	 * 
	 * @param param parameter Name
	 * @return value of the param as integer
	 */
	public int getInt(String param) {
		return Integer.parseInt(getValue(param));
	}
	/**
	 * 
	 * @return params set. You can use to iterate params to get values.
	 */
	public Set getParams() {
		return paramValuePairs.keySet();
	}
	/**
	 * printable command
	 */
	public String toString() {
		return "ver:"+this.versionID+" cmd:"+commandID+" "+paramValuePairs;	
	}
	/**
	 * output for transfer
	 */
	public String output() {
		StringBuffer strbuf = new StringBuffer();
		strbuf.append(versionID);
		strbuf.append(commandSeparator);
		strbuf.append(commandID);
		Set entryset = this.paramValuePairs.entrySet();
		Iterator iter = entryset.iterator();
		while (iter.hasNext()) {
			Map.Entry entry = (Map.Entry)(iter.next());
			strbuf.append(commandSeparator);
			strbuf.append(entry.getKey());
			strbuf.append(paramSeparator);
			strbuf.append(entry.getValue());
		}
		return strbuf.toString();
	}
	
	public String getVersionID() {
	    return this.versionID;
	}
	private static Logger logger = Logger.getLogger(PVCommand.class);
    /* (non-Javadoc)
     * @see protocol.Command#decode(core.ProcessThread)
     */
    public void decode(ProcessThread thd) throws SQLException {
    	String cmdID = this.getCommandID();
    	PVCommandDecoder decoder = decoderMap.get(cmdID);
    	if (decoder == null) {
    		logger.error("unsupported PVCommand:"+this);
    	} else {
    		try {
    			decoder.decode(this, thd);
			} catch (Exception e) {
	        	throw new RuntimeException(e);
	        }
    	}
        
    }
    
    public boolean existParam(String paramName) {
    	return this.paramValuePairs.containsKey(paramName);
    }
    
    public boolean equals(Object o) {
        if (!(o instanceof PVCommand))
            return false;
        PVCommand cmd = (PVCommand)o;
        return (this.versionID.equals(cmd.versionID) && this.commandID.equals(cmd.commandID)
                && this.paramValuePairs.equals(cmd.paramValuePairs));
    }
}
